<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>

</body>
<script>
    // ES5提供了一些读取或操作属性特性的方法，前面用到的Object.defineProperty就是其中之一。我总结了一些比较常用的方法如下：
    //【1】Object.defineProperty
    // Object.defineProperty(obj,propName,descriptor);

    // defineProperty有点类似于定于在Object上的静态方法，通过Object直接调用，它接收3个参数：
    // obj：需要定义属性的对象
    // propNane：需要被定义的属性名称
    // defineProperty：属性描述符，包含一些属性的特性定义

    //示例
    var obj = {};
    Object.defineProperty(obj, "name", {
        value: "name",
        configurable: true,
        writable: true,
        enumerable: true
    });

    // 【2】Object.defineProperties
    // 和defineProperty类似，是用来定义对象属性的，不同的是它可以用来同时定义多个属性，我们通过命名也可以看出来，用法如下：
    var obj = {};
    Object.defineProperties(obj, {
        "name": {
            value: "name",
            configurable: true,
            writable: true,
            enumerable: true
        },
        "age": {
            value: 20
        }
    });
    // 【3】Object.getOwnPropertyDescriptor
    // ES5中还提供了一个读取特性值的方法， 该方法接收对象及其属性名作为两个参数， 返回一个对象， 
    // 根据属性类型的不同， 返回对象会包含不同的值。
    var person = {
        age: 18,
        type: "小孩"
    }
    Object.defineProperty(person, "age", {
        get: function() {
            return this._age;
        },
        set: function(newValue) {
            this._age = newValue;
            this.type = newValue > 17 ? "成人" : "小孩";
        }
    })

    console.log(Object.getOwnPropertyDescriptor(person, "type"));
    //Object {value: "成人", writable: true, enumerable: true, configurable: true}

    //【知识点】属性的特性只能是访问器描述符和数据描述符中的一种，给已有的数据属性加get或set转换为访问器属性时，
    // 其属性的value、writable就会被废弃。

    console.log(Object.getOwnPropertyDescriptor(person, "age"));
    // {get: ƒ, set: ƒ, enumerable: true, configurable: true}【此处可以观察到，value属性和writable属性被废弃掉了】

    console.log(person.age); //undefined【因为对已经有数据属性的对象添加了访问器属性，所以value属性被废弃】
    console.log(person.type); //小孩
    console.log(person.propertyIsEnumerable("age")); //true

    // 设置get和set其中任意一个即可转换为访问器属性

    // 【重要知识点，在get和set内部，我们使用this._属性名，去抓取声明的对象内部属性】
    var person8 = {
        name: "teacher",
        _age: 12
    };
    Object.defineProperty(person8, "age", {
        get: function() {
            console.log(this)
            return this._age; // 此时不要使用this.age,会导致无限递归
        },
        set: function(newVal) {
            debugger
            this._age = newVal + "sky";
        }
    })
    person8.age = 14;
    var res = person8.age; // Object {name: "teacher" , _age : 12} 12
    console.log(res);
</script>

</html>